#-*- codeing = utf-8 -*-
#@Time : 2020/9/10 15:11
#@Author : 阳某
#@File : test2.py
#@Software : PyCharm
'''
生产者与消费者模型，解决线程的同步和线程安全
Python的Queue模块中提供了同步的、线程安全的队列类，包括FIFO（先入先出)队列Queue，LIFO（后入先出）队列LifoQueue，
和优先级队列PriorityQueue。这些队列都实现了锁原语（可以理解为原子操作，即要么不做，要么就做完），
能够在多线程中直接使用，可以使用队列来实现线程间的同步。

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯，
而通过阻塞队列来进行通讯，所以生产者生产完数据之后不用等待消费者处理，直接扔给阻塞队列，消费者不找生产者要数据，
而是直接从阻塞队列里取，阻塞队列就相当于一个缓冲区，平衡了生产者和消费者的处理能力。
这个阻塞队列就是用来给生产者和消费者解耦的。纵观大多数设计模式，都会找一个第三者出来进行解耦。
class Producer(threading.Thread):
    def run(self) -> None:
        global queue
        count = 0
        while True:
            if queue.qsize()<1000:
                for i in range(100):
                    count = count +1
                    msg = '生产成品' + str(count)
                    queue.put(msg)
                    print(msg)
            time.sleep(0.5)

class Consumer(threading.Thread):
    def run(self) -> None:
        global queue
        while True:
            if queue.qsize()>100:
                for i in range(3):
                    msg = self.name + '消费者' + queue.get()
                    print(msg)
            time.sleep(1)

if __name__ == '__main__':
    queue = Queue()
    for i in range(500):
        queue.put('初始产品'+str(i))
    for i in range(2):
        p = Producer()
        p.start()
    for i in range(5):
        c = Consumer()
        c.start()
'''


'''
在多线程环境下，每个线程都有自己的数据。一个线程使用自己的局部变量比使用全局变量好，
因为局部变量只有线程自己能看见，不会影响其他线程，而全局变量的修改必须加锁。

全局变量local_school就是一个ThreadLocal对象，每个Thread对它都可以读写student属性，但互不影响。
你可以把local_school看成全局变量，但每个属性如local_school.student都是线程的局部变量，可以任意读写而互不干扰，
也不用管理锁的问题，ThreadLocal内部会处理。

可以理解为全局变量local_school是一个dict，不但可以用local_school.student，还可以绑定其他变量，如local_school.teacher等等。
ThreadLocal最常用的地方就是为每个线程绑定一个数据库连接，HTTP请求，用户身份信息等，
这样一个线程的所有调用到的处理函数都可以非常方便地访问这些资源。

一个ThreadLocal变量虽然是全局变量，但每个线程都只能读写自己线程的独立副本，互不干扰。
ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题
# 创建全局ThreadLocal对象:
local_school = threading.local()
def process_student():
    # 获取当前线程关联的student:
    std = local_school.student
    print('Hello, %s (in %s)' % (std, threading.current_thread().name))
def process_thread(name):
    # 绑定ThreadLocal的student:
    local_school.student = name
    process_student()
t1 = threading.Thread(target= process_thread, args=('咸鱼',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('普拉思',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()
'''
from queue import Queue
import threading
import time

'''
同步调用和异步调用？
同步调用就是你喊你朋友吃饭，你朋友在忙，你就一直在那等，等你朋友忙完了 ，你们一起去。
异步调用就是你喊你朋友吃饭，你朋友说知道了，待会忙完去找你 ，你就去做别的了。
from multiprocessing import Pool
import time
import os
def test():
    print("---进程池中的进程---pid=%d,ppid=%d--"%(os.getpid(),os.getppid()))
    for i in range(3):
        print("----%d---"%i)
        time.sleep(1)
    return "hahah"
def test2(args):
    print("---callback func--pid=%d"%os.getpid())
    print("---callback func--args=%s"%args)
pool = Pool(3)
pool.apply_async(func=test,callback=test2)
time.sleep(5)
print("----主进程-pid=%d----"%os.getpid())
输出：
---进程池中的进程---pid=9401,ppid=9400--
----0---
----1---
----2---
---callback func--pid=9400
---callback func--args=hahah
----主进程-pid=9400----
'''

'''
Python全局解释锁（GIL）简单来说就是一个互斥体（或者说锁），这样的机制只允许一个线程来控制Python解释器。
这就意味着在任何一个时间点只有一个线程处于执行状态。
所以在python中多线程是假的，因为在执行过程中CPU中只有一个线程在执行。
当你使用多进程时，你的效率是高于多线程的。
Python GIL经常被认为是一个神秘而困难的话题，但是请记住作为一名Python支持者，
只有当您正在编写C扩展或者您的程序中有计算密集型的多线程任务时才会被GIL影响。
'''